import { TableSchema } from '../schema/schema';
import { ElementPropertyConfig } from '@farris/ide-property-panel';
import { TableProp } from '../property/table-property-config';
import { BuilderHTMLElement, BuilderOptions } from '@farris/designer-element';
import FdCollectionBaseComponent from '../../common/collection-base/fd-collection-base';
import FdTableTdComponent from './fd-table-td';
import { FormPropertyChangeObject } from '../../../../entity/property-change-entity';
import { TableTdManager } from './td-manager/td-manager';
import { ControlCssLoaderUtils } from '../../../../utils/control-css-loader';
import { SimpleTableTdManager } from './td-manager/td-manager-simple';
import FdTableEmptyTdComponent from './fd-table-empty-td';
import { DesignerEnvType, DesignViewModelService, FormBasicService, FormBindingType, SchemaService } from '@farris/designer-services';

export default class FdTableComponent extends FdCollectionBaseComponent {

    /** 单元格实例 */
    private tdComponents = [];

    /** 单元格模板 */
    private tdComponentElements = [];

    /* 标识td的key值 */
    get tdLinkKey(): string {
        return `td-${this.key}`;
    }
    get tdWidgetLinkKey(): string {
        return `td-widget-${this.key}`;
    }

    private tdManager: TableTdManager;

    constructor(component: any, options: BuilderOptions) {
        super(component, options);

        // 加载css相关文件
        ControlCssLoaderUtils.loadCss('table.css');

        this.applyClassToComponent = false;

        const injector = options.designerHost.getService('Injector');

        if (this.component.devMode === 'simple') {
            this.tdManager = new SimpleTableTdManager(component, injector);
        } else {
            this.tdManager = new TableTdManager(component, injector);
        }

        this.tdManager.redrawTable.subscribe((data: any) => {

            if (data && data.refreshPropertyPanel) {
                this.triggerTdClick(this.tdManager.targetTdElement);
            }
            if (data && data.clearPropertyPanel) {
                this.emit('clearPropertyPanel');
            }
            this.rebuild();
        });
    }


    getDefaultSchema(): any {
        return TableSchema;
    }


    getTemplateName(): string {
        return 'Table';
    }
    /** padding是为了解决table不显示边框的问题 */
    getStyles(): string {
        return ' display: block;padding:1px;';
    }


    getClassName(): string {
        let clsName = super.getClassName();
        if (this.component.devMode === 'simple') {
            clsName += ' simpleTable';
        }
        return clsName;
    }
    /**
     * 判断是否可以接收拖拽新增的子级控件
     */
    canAccepts(el: BuilderHTMLElement) {
        return false;
    }
    /**
     * 去掉间距和线条
     */
    hideNestedPaddingInDesginerView(): boolean {
        return true;
    }

    getInnerComponentInstance() {
        return this.tdComponents;
    }
    init(): void {
        this.adaptOldControlSchema();
        this.components = [];
        this.tdComponents = [];
        this.tdManager.viewModelId = this.viewModelId;

        const isSimpleTable = this.component.devMode === 'simple';
        const options = Object.assign({}, this.options, { parent: this });
        this.component.rows.forEach((row, rowIndex) => {
            if (!row.columns || !row.columns.length) {
                return;
            }
            this.tdComponents[rowIndex] = {};
            this.tdComponentElements[rowIndex] = {};

            row.columns.forEach((column, columnIndex) => {
                let isEmptyTd = true;
                if (column.tdType === 'editor' && column.editor && column.editor.type) {
                    const editorComponent: any = this.createComponent(column.editor, options, null);

                    this.tdComponentElements[rowIndex][columnIndex] = this.renderComponents([editorComponent]);

                    isEmptyTd = false;
                }
                if (column.tdType === 'staticText' && column.staticText.text) {
                    isEmptyTd = false;
                }
                const columnCmp = isSimpleTable && isEmptyTd ? new FdTableEmptyTdComponent(column, options) : new FdTableTdComponent(column, options);

                this.tdComponents[rowIndex][columnIndex] = columnCmp;
                this.components.push(columnCmp);
            });

        });

    }

    render(): any {
        return super.render(this.renderTemplate('Table', {
            tdComponents: this.tdComponentElements,
            tdLinkKey: this.tdLinkKey,
            targetTdId: this.tdManager.targetTdId,
            targetMergedTdIds: this.tdManager.targetMergedTdIds,
            tdWidgetLinkKey: this.tdWidgetLinkKey,
            nestedKey: this.nestedKey,
            checkTdCanDragAndDrop: (column: any, tdELement: string, devMode: string) => this.checkTdCanDragAndDrop(column, tdELement, devMode),
            getSelectedBorderStyle: (column: any) => this.getSelectedBorderStyle(column)
        }));
    }

    attach(element: HTMLElement): Promise<any> {
        this.loadRefs(element, {
            [this.tdLinkKey]: 'multiple',
            [this.tdWidgetLinkKey]: 'multiple',
            contextMenu: 'single'
        });

        const superAttach: any = super.attach(element);

        // 注册单元格选中事件
        if (this.refs[this.tdLinkKey] && this.refs[this.tdLinkKey].length) {
            this.refs[this.tdLinkKey].forEach((tdEle, index) => {

                this.addEventListener(tdEle, 'click', (event: MouseEvent) => {
                    event.preventDefault();
                    event.stopPropagation();

                    this.triggerTdClick(tdEle, event);
                });
            });
        }

        // 注册单元格操作图标的点击事件
        if (this.refs[this.tdWidgetLinkKey] && this.refs[this.tdWidgetLinkKey].length) {
            this.refs[this.tdWidgetLinkKey].forEach((widgetEle, index) => {

                this.addEventListener(widgetEle, 'click', (event: MouseEvent) => {
                    this.showTdManageContext(event, widgetEle);
                });
            });
        }

        // 简单类表格要支持拖拽，所以给单元格附加操作
        // if (this.component.devMode === 'simple') {
        this.component.rows.forEach((row, rowIndex: number) => {
            if (!row.columns || !row.columns.length) {
                return;
            }
            row.columns.forEach((column, columnIndex) => {
                if (this.tdComponents[rowIndex] && this.tdComponents[rowIndex][columnIndex]) {

                    const tdElement = Array.from(this.refs[this.tdLinkKey]).find((tdEle: HTMLElement) => tdEle.getAttribute('id') === column.id);
                    if (tdElement) {
                        this.tdComponents[rowIndex][columnIndex].attach(tdElement);
                    }
                }
            });

        });
        // }

        return superAttach;
    }

    /**
     * 点击单元格
     * @param tdEle 单元格DOM元素
     * @param event 事件
     */
    triggerTdClick(tdEle: HTMLElement, event?: MouseEvent) {
        // 简单表格
        if (this.component.devMode === 'simple') {
            this.triggerMegedTdClick(tdEle, event);
            return;
        }

        // 高级表格
        this.tdManager.targetTdElement = tdEle;
        this.tdManager.targetTdId = tdEle.getAttribute('id');
        this.getTargetColumnData(this.tdManager.targetTdId);

        this.tdComponents[this.tdManager.selectedRowIndex][this.tdManager.selectedColumnIndex].triggerComponentClicked(tdEle, event);
    }

    /**
     * 简单类表格在点击单元格时，要同时选中标签类单元格和编辑器类单元格，视觉上认为标签和编辑器是一个单元格
     * @param tdEle 用户点击的单元格DOM元素
     * @param event 事件
     */
    triggerMegedTdClick(tdEle: HTMLElement, event?: MouseEvent) {

        const groupId = tdEle.getAttribute('groupid');
        const { tdElements: tdElementsInSameGroup, activeEditorTdElement } = this.getTdElementsInSameGroup(groupId);

        if (!tdElementsInSameGroup || !activeEditorTdElement) {
            return;
        }
        // 增加边框
        this.tdManager.targetMergedTdIds = [];
        this.clearSelected();
        tdElementsInSameGroup.forEach(td => {
            this.tdManager.targetMergedTdIds.push(td.getAttribute('id'));
            td.classList.add('dgComponentSelected');
            this.addSelectedBorderToSimpleTableTd(td);
        });

        // 定位组内编辑器类型的单元格实例，即实际选中单元格
        this.tdManager.targetTdElement = activeEditorTdElement;
        this.tdManager.targetTdId = activeEditorTdElement.getAttribute('id');
        this.getTargetColumnData(this.tdManager.targetTdId);




        // 简单类表格的静态文本类单元格，支持直接在画布中修改文本
        const staticTd = tdElementsInSameGroup.find(tdEle => tdEle.component && tdEle.component.component && tdEle.component.component.tdType === 'staticText');
        if (staticTd && this.envType === DesignerEnvType.noCode) {
            this.registerStaticTdContentEditable(staticTd, activeEditorTdElement);
        }


        // 切换到组内编辑器单元格的属性面板
        this.emit('componentClicked', {
            componentInstance: this.tdComponents[this.tdManager.selectedRowIndex][this.tdManager.selectedColumnIndex],
            needUpdatePropertyPanel: true,
            e: event
        });
    }
    /**
     * 清除页面上之前的选中状态
     */
    clearSelected() {
        const currentSelectedElements = document.getElementsByClassName('dgComponentSelected');
        for (const ele of Array.from(currentSelectedElements)) {
            ele.classList.remove('dgComponentSelected');

            //  移除选中状态下的边框宽度
            if (ele && ele['componentInstance'] && ele['componentInstance'].type === 'TableTd') {
                const tdStyle = ele.getAttribute('style');
                if (tdStyle) {
                    const styleWithoutBorderWidth = tdStyle.split(';').filter(style => style && !style.startsWith('border-'));
                    ele.setAttribute('style', styleWithoutBorderWidth.join(';'));

                }
            }

        }
    }

    /**
     * 单元格选中状态下增加边框宽度，宽度需要比table配置的边框宽度大1px，否则页面无法显示蓝色边框
     * @param td 单元格元素
     */
    addSelectedBorderToSimpleTableTd(td: HTMLElement) {
        if (!td.getAttribute('style').includes('border-top-width')) {
            const borderWidth = this.component.border && !this.isEmptyValue(this.component.border.width) ? this.component.border.width : 1;
            const selectedborderWidth = borderWidth + 1;

            let tdStyle = td.getAttribute('style');
            tdStyle += ';border-top-width:' + selectedborderWidth + 'px !important;';
            tdStyle += 'border-bottom-width:' + selectedborderWidth + 'px !important;';

            // 标签单元格显示左边线，编辑器单元格显示右边框
            if (td.getAttribute('tdtype') === 'staticText') {
                tdStyle += 'border-left-width:' + selectedborderWidth + 'px !important;';
            }
            if (td.getAttribute('tdtype') === 'editor') {
                tdStyle += 'border-right-width:' + selectedborderWidth + 'px !important;';
            }
            td.setAttribute('style', tdStyle);
        }
    }

    /**
     * 单元格选中状态下增加边框宽度，用于模板form.ts中使用
     * @param column 单元格schema
     */
    getSelectedBorderStyle(column: any): string {
        const borderWidth = this.component.border && !this.isEmptyValue(this.component.border.width) ? this.component.border.width : 1;
        const selectedborderWidth = borderWidth + 1;
        let borderStyle = '';
        // 简单表格的单元格的选中边框
        if (this.component.devMode === 'simple') {
            borderStyle =
                ';border-top-width:' + selectedborderWidth + 'px !important' +
                ';border-bottom-width:' + selectedborderWidth + 'px !important';

            // 标签单元格显示左边线，编辑器单元格显示右边框
            if (column.tdType === 'staticText') {
                borderStyle += ';border-left-width:' + selectedborderWidth + 'px !important';
            }
            if (column.tdType === 'editor') {
                borderStyle += ';border-right-width:' + selectedborderWidth + 'px !important';
            }

        } else {
            // 高级表格的单元格选中边框
            borderStyle = ';border-width:' + selectedborderWidth + 'px !important';
        }

        return borderStyle;
    }

    /**
     * 获取单元格DOM元素
     * @param targetTdId 单元格id
     */
    getTdElement(targetTdId: string) {
        if (this.refs[this.tdLinkKey] && this.refs[this.tdLinkKey].length) {
            for (const tdEle of this.refs[this.tdLinkKey]) {
                const tdId = tdEle.getAttribute('id');
                if (tdId === targetTdId) {
                    return tdEle;
                }
            }

        }
    }

    /**
     * 获取同组的单元格DOM元素
     * @param targetTdId 单元格id
     */
    getTdElementsInSameGroup(targetGroupId: string): {
        tdElements: BuilderHTMLElement[],
        activeEditorTdElement: HTMLElement,
        labelTdElement: HTMLElement
    } {
        const tdElements = [];
        let activeEditorTdElement;
        let labelTdElement;
        if (this.refs[this.tdLinkKey] && this.refs[this.tdLinkKey].length) {
            for (const tdEle of this.refs[this.tdLinkKey]) {
                const groupId = tdEle.getAttribute('groupid');
                const tdType = tdEle.getAttribute('tdtype');
                const tdCls = tdEle.getAttribute('class');
                if (groupId && groupId === targetGroupId) {
                    tdElements.push(tdEle);
                    // 取当前显示在界面上的编辑器单元格
                    if (tdType === 'editor' && tdCls && !tdCls.includes('d-none')) {
                        activeEditorTdElement = tdEle;
                    }
                    if (tdType === 'staticText' && tdCls && !tdCls.includes('d-none')) {
                        labelTdElement = tdEle;
                    }
                }
            }
        }

        return { tdElements, activeEditorTdElement, labelTdElement };
    }

    /**
     * 组装属性面板配置数据
     */
    getPropertyConfig(): ElementPropertyConfig[] {
        const serviceHost = this.options.designerHost;
        const prop: TableProp = new TableProp(serviceHost, this.viewModelId, this.componentId);
        const propertyConfig: ElementPropertyConfig[] = prop.getPropConfig(this.component, this.tdManager);
        return propertyConfig;
    }
    /**
     * 属性变更后
     * @param changeObject 变更集
     */
    onPropertyChanged(changeObject: FormPropertyChangeObject): void {
        // 触发重绘
        const dynamicPropIds = ['staticText.require', 'staticText.text', 'tdType', 'editor.require', 'editor.title', 'editor.placeHolder'];
        super.onPropertyChanged(changeObject, dynamicPropIds);

        // 切换编辑器：因为涉及变动的属性太多，故触发属性面板的整体重绘
        if (changeObject.categoryId === 'tdType' || changeObject.categoryId.includes('editorBinding')) {
            this.triggerTdClick(this.tdManager.targetTdElement);
        }

        // 切换编辑器需要触发重构
        if (changeObject['controlEditorChanged']) {
            this.rebuild();
        }
        // 修改扩展区域、枚举项需要触发重构
        if (['enableAppend', 'inputAppendText', 'inputAppendType', 'enumData', 'items'].includes(changeObject.propertyID)) {
            this.rebuild();
        }
        // 修改边框、字体等需要触发重构
        if (['font', 'border'].includes(changeObject.categoryId)) {
            this.rebuild();
        }
    }

    /**
     * 获取选中单元格的行、列信息
     * @param targetTdId 单元格id
     */
    private getTargetColumnData(targetTdId: string) {
        if (!this.component.rows) {
            return;
        }

        for (let rowIndex = 0; rowIndex < this.component.rows.length; rowIndex++) {
            const row = this.component.rows[rowIndex];
            for (let colIndex = 0; colIndex < row.columns.length; colIndex++) {
                const column = row.columns[colIndex];
                if (column.id === targetTdId) {
                    this.tdManager.selectedColumnIndex = colIndex;
                    this.tdManager.selectedRowIndex = rowIndex;

                    this.tdManager.targetColumn = column;
                    this.tdManager.targetRow = row;
                }
            }
        }
    }
    /**
     * 显示菜单
     * @param event 点击事件
     * @param widgetEle 图标元素
     */
    private showTdManageContext(event: MouseEvent, widgetEle: HTMLElement) {
        event.preventDefault();
        event.stopPropagation();

        if (!this.tdManager.targetColumn || !this.tdManager.targetRow) {
            return;
        }
        this.tdManager.showContextMenu(event, widgetEle);
    }

    /**
     * 简单类表格的单元格是否可以拖拽，是否可以接收拖拽内容
     * @param column 单元格元数据
     * @param tdElement 单元格元素
     */
    private checkTdCanDragAndDrop(column: any, tdElement: string, devMode: string) {

        if (!tdElement) {
            return '';
        }

        // 高级表格不允许拖动
        if (devMode !== 'simple') {
            tdElement = tdElement.replace('inputInTable', 'inputInTable no-drag no-drop');
            tdElement = tdElement.replace('farris-label-wrap', 'farris-label-wrap no-drag no-drop');
            return tdElement || '';
        }

        // 1、标签类单元格
        if (column.tdType === 'staticText') {
            // 有值：可以拖走，不接收外部拖拽
            if (column.staticText && column.staticText.text) {
                tdElement = tdElement.replace('farris-label-wrap', 'farris-label-wrap no-drop');
            } else {
                // 空白单元格：不支持拖走，可以接收外部拖拽
                tdElement = tdElement.replace('farris-label-wrap', 'farris-label-wrap no-drag');
            }
        } else {
            // 2、编辑器单元格：不支持拖走，不接收外部拖拽
            tdElement = tdElement.replace('inputInTable', 'inputInTable no-drag no-drop');
        }

        return tdElement || '';

    }

    isEmptyValue(value: any) {
        if (value === null || value === undefined) {
            return true;
        }
    }

    /**
     * 适配表单控件的元数据变更
     */
    private adaptOldControlSchema() {
        if (!this.component) {
            return;
        }
        delete this.component.borderWidth;
        delete this.component.borderColor;
    }



    /**
     * 注册label标签的编辑事件
     */
    private registerStaticTdContentEditable(staticTd: BuilderHTMLElement, editorTd: BuilderHTMLElement) {
        if (!staticTd || !editorTd) {
            return;
        }
        const labelSpanEle = staticTd.querySelector('.farris-label-text');
        if (!labelSpanEle) {
            return;
        }
        if (labelSpanEle.getAttribute('contenteditable')) {
            return;
        }
        // 启用标签编辑属性
        labelSpanEle.setAttribute('contenteditable', 'true');

        // 监听标签blur事件
        this.addEventListener(labelSpanEle, 'blur', (e) => {
            const newTitle = e.target.innerText;
            const staticTdSchema = staticTd.component.component;
            const editorTdSchema = editorTd.component.component;

            if (staticTdSchema.staticText.text !== newTitle) {

                // 更新控件DOM
                staticTdSchema.staticText.text = newTitle;
                editorTdSchema.editor.title = newTitle;

                // 更新属性面板
                this.emit('componentClicked', {
                    componentInstance: this.tdComponents[this.tdManager.selectedRowIndex][this.tdManager.selectedColumnIndex],
                    needUpdatePropertyPanel: true,
                    e
                });


                // 控件绑定字段：触发更新schema变更
                if (editorTdSchema.editor.binding && editorTdSchema.editor.binding.type === FormBindingType.Form) {
                    this.syncSchemaFieldAfterControlTitleChanged(editorTdSchema.editor.binding.field, newTitle);
                }

            }

        });
    }
    /** 
     * 修改控件标签后，同步schema字段
     */
    private syncSchemaFieldAfterControlTitleChanged(fieldId: string, newTitle: string) {
        // 1、同步viewModel字段增量
        const dgVMService = this.options.designerHost.getService('DesignViewModelService') as DesignViewModelService;
        const dgViewModel = dgVMService.getDgViewModel(this.viewModelId);
        const dgVMField = dgViewModel && dgViewModel.fields.find(f => f.id === fieldId);
        if (dgVMField) {
            dgViewModel.changeField(dgVMField.id, { name: newTitle });
        }

        // 2、若是零代码表单驱动模板，还需要更改schema里的字段信息
        const formBasicServ = this.options.designerHost.getService('FormBasicService') as FormBasicService;
        if (this.envType === DesignerEnvType.noCode && formBasicServ.driveMode === 'form') {
            const schemaService = this.options.designerHost.getService('SchemaService') as SchemaService;

            // 判断是否为拖拽新增的字段
            const schemaField = schemaService.getFieldByID(dgVMField.id);
            if (schemaField && schemaService.addedFieldsByControlBox.includes(dgVMField.id)) {
                schemaField.name = newTitle;
            }
        }


    }
}
